package com.excel.service.excel.v1;



import cn.hutool.core.util.ObjectUtil;
import com.corpgovernment.api.applytrip.enums.ApplyTripEmployeeEnum;
import com.corpgovernment.common.common.CorpBusinessException;
import com.corpgovernment.common.constant.RegularExpressionConst;
import com.corpgovernment.common.enums.CardEnum;
import com.corpgovernment.common.enums.GenderEnum;
import com.corpgovernment.common.enums.NationalityEnum;
import com.corpgovernment.common.enums.PhoneCountryCodeEnum;
import com.corpgovernment.common.utils.DateUtil;
import com.corpgovernment.common.utils.ObjectStringTrimUtils;
import com.corpgovernment.job.dao.entity.db.JobDo;
import com.corpgovernment.job.dao.entity.db.JobOrgRelationDo;
import com.corpgovernment.job.dao.mapper.JobMapper;
import com.corpgovernment.job.dao.mapper.JobOrgRelationMapper;
import com.corpgovernment.job.service.JobService;
import com.corpgovernment.job.service.bo.JobBo;
import com.corpgovernment.organization.Bo.SyncEmployeeInfoBo;
import com.corpgovernment.organization.constant.OrganizationResponseCodeEnum;
import com.corpgovernment.organization.entity.SyncEmployeeCallBackRequestEntity;
import com.corpgovernment.organization.entity.db.*;
import com.corpgovernment.organization.enumm.ServiceErrorEnum;
import com.corpgovernment.organization.service.IOrgUserIdCardService;
import com.corpgovernment.organization.service.IOrganizationEmployeeService;
import com.corpgovernment.organization.service.IOrganizationInfoService;
import com.corpgovernment.organization.service.IPostService;
import com.corpgovernment.organization.util.ExcelUtils;
import com.corpgovernment.organization.util.IdCardUtil;
import com.corpgovernment.organization.util.StrUtils;
import com.corpgovernment.organization.vo.EmployeeCardTypeInfoColumnVO;
import com.corpgovernment.organization.vo.EmployeeInfoExcelColumnVO;
import com.corpgovernment.permission.entity.db.MbRole;
import com.corpgovernment.permission.service.RoleService;
import com.ctrip.corp.obt.generic.utils.CollectionUtils;
import com.ctrip.corp.obt.generic.utils.EncryptUtils;
import com.ctrip.corp.obt.generic.utils.JsonUtils;
import com.ctrip.corp.obt.generic.utils.StringUtils;
import com.excel.model.ExcelImportConfig;
import com.excel.qlexpress.CommonQlFunction;
import com.excel.qlexpress.EmployQlFunction;
import com.excel.qlexpress.ImportQlUtils;
import com.excel.service.excel.*;
import com.excel.util.ExcelImportUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.corpgovernment.common.enums.GenderEnum.F;
import static com.corpgovernment.common.enums.GenderEnum.M;

/**
 * 员工
 *
 * @author hc
 */
@Service
@Slf4j
public class EmployAddProcessorV1<T> implements ExcelImportProcessor<SyncEmployeeCallBackRequestEntity.FailInfo,SyncEmployeeInfoBo, MbImportExcelRecord, T> {

    @Autowired
    private ExcelUtils excelUtils;
    @Autowired
    private IOrganizationInfoService organizationInfoService;
    @Autowired
    private IPostService postService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private IOrganizationEmployeeService organizationEmployeeService;
    @Autowired
    private JobService jobService;
    @Resource
    private JobOrgRelationMapper jobOrgRelationMapper;
    @Autowired
    private ExcelImportUtil excelImportUtil;
    @Resource
    private JobMapper jobMapper;
    @Autowired
    private IOrgUserIdCardService organizationUserIdCardService;

    private static final String ENCRYPT_KEY = "1234567890123456";


    @Override
    public List<SyncEmployeeInfoBo> assembleListFromExcel(MbImportExcelRecord mbImportExcelRecord) {
        return null;
    }

    @Override
    public  BizImportResult<SyncEmployeeCallBackRequestEntity.FailInfo,SyncEmployeeInfoBo> assembleListFromExcel(MbImportExcelRecord mbImportExcelRecord, MultipartFile file) {

        BizImportResultImpl<SyncEmployeeCallBackRequestEntity.FailInfo,SyncEmployeeInfoBo> result = new BizImportResultImpl<>();

        List<SyncEmployeeCallBackRequestEntity.FailInfo> errorList = new ArrayList<>();
        List<SyncEmployeeInfoBo> empList = new ArrayList<>();

        // 获取excel资源
        XSSFWorkbook workBook = null;
        try {
            workBook = new XSSFWorkbook(file.getInputStream());
        } catch (IOException e) {
            log.error("上传异常", e);
            throw new CorpBusinessException(OrganizationResponseCodeEnum.FILE_WRONG_FORMAT);
        }

        XSSFSheet sheetOrg = workBook.getSheet("员工");
        List<EmployeeInfoExcelColumnVO> employeeInfo = excelUtils.getBeanListFromExcelTwo(sheetOrg, EmployeeInfoExcelColumnVO.class);

        //获取证件数据
        XSSFSheet sheetDelivery = workBook.getSheet("证件");
        List<EmployeeCardTypeInfoColumnVO> empCardType = excelUtils.getBeanListFromExcel(sheetDelivery, EmployeeCardTypeInfoColumnVO.class);

        employeeInfo.forEach(t ->  ObjectStringTrimUtils.allFieldRemoveWarp(t));
        empCardType.forEach(t ->  ObjectStringTrimUtils.allFieldRemoveWarp(t));

        //将证件信息——>Map
        Map<String, List<EmployeeCardTypeInfoColumnVO>> empCardMap = empCardType.stream().
                filter(item -> Objects.nonNull(item) && StringUtils.isNotBlank(item.getUid())).collect(Collectors.groupingBy(item -> item.getUid()));

        confirmGenderAndBirthDay(empCardMap, employeeInfo);


        //将员工绑定证件
        for (EmployeeInfoExcelColumnVO item : employeeInfo) {
            SyncEmployeeInfoBo employeeInfoBo =  buildEmployeeInfoBo(empCardMap, item);
            empList.add(employeeInfoBo);
        }
        log.info( "组装后数据：{}", JsonUtils.toJsonString(empList));



        // Excel 重复内容检查
        List<EmployeeInfoExcelColumnVO> uidDuplicates = EmployQlFunction.getDuplicateEmployField(employeeInfo, f -> StringUtils.isBlank(f.getUid()) ? "" : f.getUid()); // 根据 uid 过滤重复数据
        List<EmployeeInfoExcelColumnVO> mobileDuplicates = EmployQlFunction.getDuplicateEmployField(employeeInfo, f -> StringUtils.isBlank(f.getMobilePhone()) ? "" : f.getMobilePhone()); // 根据 mobile 过滤重复数据
        for (EmployeeInfoExcelColumnVO item : uidDuplicates) {
            SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
            errorLog.setMainLineNo(item.getLineNo());
            errorLog.setLineNo(item.getLineNo());
            errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
            errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.EMP.getIndex());
            errorLog.setFailReason("Excel中存在相同Uid");
            errorList.add(errorLog);
        }

        for (EmployeeInfoExcelColumnVO item : mobileDuplicates) {
            SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
            errorLog.setMainLineNo(item.getLineNo());
            errorLog.setLineNo(item.getLineNo());
            errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
            errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.EMP.getIndex());
            errorLog.setFailReason("Excel中存在相同手机号");
            errorList.add(errorLog);
        }


        result.setErrorList(errorList);
        result.setDataList(empList);
        return result;
    }


    @Override
    public BizImportResult<SyncEmployeeCallBackRequestEntity.FailInfo,SyncEmployeeInfoBo> checkExcelData(List<SyncEmployeeInfoBo> list) {

        BizImportResultImpl<SyncEmployeeCallBackRequestEntity.FailInfo,SyncEmployeeInfoBo> result = new BizImportResultImpl<>();

        List<SyncEmployeeCallBackRequestEntity.FailInfo> errorList = new ArrayList<>();
        List<SyncEmployeeInfoBo> dataList = new ArrayList<>();

        // 通过qlexpress表达式校验数据内容
        for (SyncEmployeeInfoBo item : list) {
            List<String> expressGroup = new ArrayList<>(Arrays.asList(
                    "员工编号","员工国籍","员工性别","员工类型",
                    "手机国家码","手机号码","员工手机号","员工名字",
                    "员工证件","员工邮箱","员工生日"));
            Map<String, String> failMsgMap = ImportQlUtils.getCheckFailMsg(ImportQlUtils.checkEmploy(expressGroup, ImportQlUtils.buildEmployCheckContextMap(item)));
            log.info("checkExcelData failMsgMap:{}",failMsgMap);

            for (Map.Entry<String, String> entry : failMsgMap.entrySet()) {
                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(item.getLineNo());
                String value = entry.getValue();
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.EMP.getIndex());
                errorLog.setLineNo(item.getLineNo());
                errorLog.setFailReason(value);
                errorList.add(errorLog);
            }
            NationalityEnum nation = NationalityEnum.getByCode(Optional.ofNullable(item.getNationality()).orElse(NationalityEnum.CN.getCode()));
            if (nation != null) {
                item.setNationality(String.join("|", nation.getCode(), nation.getDesc()));
                item.setNationCode(nation.getCode());
                item.setNationName(nation.getDesc());
            }


            // 校验证件信息
            this.checkEmployeeCardInfo(item, errorList);

            dataList.add(item);
        }

        result.setErrorList(errorList);
        result.setDataList(dataList);
        return result;
    }

    @Override
    public BizImportPreInsertResult<SyncEmployeeCallBackRequestEntity.FailInfo, SyncEmployeeInfoBo, T> checkDbDataWithPreInsert(List<SyncEmployeeInfoBo> list) {


        BizImportPreInsertResultImpl<SyncEmployeeCallBackRequestEntity.FailInfo, SyncEmployeeInfoBo, T> result = new BizImportPreInsertResultImpl();

        List<SyncEmployeeCallBackRequestEntity.FailInfo> errorList = new ArrayList<>();
        List<SyncEmployeeInfoBo> dataList = new ArrayList<>();

        List<String> uids = list.stream().filter(f-> StringUtils.isNotBlank(f.getUid())).map(SyncEmployeeInfoBo::getUid).collect(Collectors.toList());
        List<String> businessCodes = list.stream().filter(f-> StringUtils.isNotBlank(f.getBusinessCode())).map(SyncEmployeeInfoBo::getBusinessCode).collect(Collectors.toList());
        List<String> phoneSm4Encrypts = list.stream().filter(f-> StringUtils.isNotBlank(f.getMobilePhone())).map(s -> EncryptUtils.sm4Encrypt(s.getMobilePhone(), ENCRYPT_KEY)).collect(Collectors.toList());

        Map<String, Boolean> uidMap = excelImportUtil.isExistByFieldInDb("mb_org_employee_info","uid",uids,true);

        Map<String, Boolean> businessCodeMap = excelImportUtil.isExistByFieldInDb("mb_org_info","business_code",businessCodes,true);

        Map<String, Boolean> phoneMap = excelImportUtil.isExistByFieldInDb("mb_org_employee_info","mobile_phone",phoneSm4Encrypts,true);

        Map<String, List<SyncEmployeeInfoBo>> uidEmpInfoMap = list.stream().collect(Collectors.groupingBy(SyncEmployeeInfoBo::getUid));

        // 需要新增的信息 岗位 + 职级
        List<T> needInsertList = new ArrayList<>();


        // 新增 校验db是否存在的uid phone 和 上级组织编码
        for (SyncEmployeeInfoBo item : list) {

            if(uidMap.containsKey(item.getUid()) && uidMap.get(item.getUid())){
                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(item.getLineNo());
                errorLog.setLineNo(item.getLineNo());
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.EMP.getIndex());
                errorLog.setFailReason(OrganizationResponseCodeEnum.EMPLOYEE_UID_EXIST.message());
                errorList.add(errorLog);
            }

            if(businessCodeMap.containsKey(item.getBusinessCode()) && !businessCodeMap.get(item.getBusinessCode())){
                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(item.getLineNo());
                errorLog.setLineNo(item.getLineNo());
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.EMP.getIndex());
                errorLog.setFailReason(ServiceErrorEnum.SyncHumanResources_SyncEmployeeInfo_company_Null_Failure.getErrorMessage());
                errorList.add(errorLog);
            }else {
                MbOrgInfo thisItem = organizationInfoService.findByBusinessCode(item.getBusinessCode());
                item.setOrgId(thisItem.getOrgId());
                item.setMbPostList(new ArrayList<>());
                item.setJobDoList(new ArrayList<>());
                // 获取当前excel填写的组织编码 的最近一级的公司信息 -匹配职级
                MbOrgInfo mbOrgInfo = organizationInfoService.findFirstCompany(thisItem.getOrgId());
                if(mbOrgInfo!= null){
                    item.setFirstCorgId(mbOrgInfo.getOrgId());
                    List<MbRole> mbRoles = roleService.listCorpRoles(mbOrgInfo.getOrgId());
                    item.setMbRoleList(mbRoles);
                    List<MbPostInfo> postInfos = postService.listByOrgIds(Collections.singletonList(mbOrgInfo.getOrgId()));
                    item.setMbPostList(postInfos);
                }
                List<JobDo> jobDoList = jobService.listJobBoByOrgId(item.getOrgId());
                item.setJobDoList(jobDoList);
            }

            String phoneSm4Encrypt = EncryptUtils.sm4Encrypt(item.getMobilePhone(), ENCRYPT_KEY);
            if(phoneMap.containsKey(phoneSm4Encrypt) && phoneMap.get(phoneSm4Encrypt)){
                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(item.getLineNo());
                errorLog.setLineNo(item.getLineNo());
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.EMP.getIndex());
                errorLog.setFailReason(OrganizationResponseCodeEnum.EMPLOYEE_PHONE_NO_EXIST.message());
                errorList.add(errorLog);
            }
            // 职级校验
            checkPostFromDb(errorList, needInsertList, item);


            ServiceErrorEnum superiorErrorEnum = this.checkSuperiorInfo(item.getManageUid(),uidEmpInfoMap);
            if (!ServiceErrorEnum.Success.getErrorCode().equals(superiorErrorEnum.getErrorCode())) {
                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(item.getLineNo());
                errorLog.setLineNo(item.getLineNo());
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.EMP.getIndex());
                errorLog.setFailReason(superiorErrorEnum.getErrorMessage());
                errorList.add(errorLog);
            }

            ServiceErrorEnum employeeRoleNameErrorEnum = this.checkEmployeeRoleName(item);
            if (!ServiceErrorEnum.Success.getErrorCode().equals(employeeRoleNameErrorEnum.getErrorCode())) {
                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(item.getLineNo());
                errorLog.setLineNo(item.getLineNo());
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.EMP.getIndex());
                errorLog.setFailReason(employeeRoleNameErrorEnum.getErrorMessage());
                errorList.add(errorLog);
            }

            // 岗位校验
            checkJobFromDb(errorList, needInsertList, item);

            // 证件校验
            checkCardListFromDb(errorList, item);

            //没传密码取值为手机后8位
            String mobilePhone = item.getMobilePhone();
            item.setPassword(Optional.ofNullable(item.getPassword()).orElse(CommonQlFunction.buildNewPwd(mobilePhone)));

            dataList.add(item);
        }

        result.setErrorList(errorList);
        result.setDataList(dataList);
        result.setPreInsertList(needInsertList);
        return result;
    }

    public void checkCardListFromDb(List<SyncEmployeeCallBackRequestEntity.FailInfo> errorList, SyncEmployeeInfoBo item) {
        item.getCardInfoList().forEach(cardType -> {
            List<MbOrgUserIdcard> mbOrgUserIdcards = organizationUserIdCardService
                    .findByTypeAndNo(Integer.valueOf(cardType.getCardType()), cardType.getCardNo(), false);
            if (!CollectionUtils.isEmpty(mbOrgUserIdcards)) {
                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(item.getLineNo());
                errorLog.setLineNo(cardType.getLineNo());
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.CARD.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.CARD.getIndex());
                errorLog.setFailReason(OrganizationResponseCodeEnum.CARD_EXISTS.message());
                errorList.add(errorLog);
            }
        });
    }

    public void checkJobFromDb(List<SyncEmployeeCallBackRequestEntity.FailInfo> errorList, List<T> needInsertJobList, SyncEmployeeInfoBo item) {

        if(StringUtils.isNotBlank(item.getJobCode()) && StringUtils.isNotBlank(item.getJobName())){
            Optional<JobDo> mbJobInfo = item.getJobDoList().stream().filter(i ->item.getJobCode().equalsIgnoreCase(i.getCode())).findFirst();
            if (mbJobInfo.isPresent() && !mbJobInfo.get().getName().equals(item.getJobName())) {

                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(item.getLineNo());
                errorLog.setLineNo(item.getLineNo());
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.EMP.getIndex());
                errorLog.setFailReason("岗位名称不存在，且不可导入");
                errorList.add(errorLog);
                return;
            }
            if (!mbJobInfo.isPresent()) {
                JobDo bo = new JobDo();
                bo.setName(item.getJobName());
                bo.setCode(item.getJobCode());
                needInsertJobList.add((T) bo);
                return;
            }
        }

        if(StringUtils.isBlank(item.getJobCode()) && StringUtils.isNotBlank(item.getJobName())){
            Optional<JobDo> mbJobInfo = item.getJobDoList().stream().filter(i ->item.getJobName().equalsIgnoreCase(i.getName())).findFirst();
            if (!mbJobInfo.isPresent()) {
                JobDo bo = new JobDo();
                bo.setName(item.getJobName());
                bo.setCode(item.getJobCode());
                needInsertJobList.add((T) bo);
                return;
            }
        }

        // 填充 岗位id
        if(StringUtils.isNotBlank(item.getJobName())){
            JobDo jobDo = jobMapper.getByName(item.getJobName());
            if(jobDo!=null){
                item.setJobId(jobDo.getId());
                item.setJobCode(jobDo.getCode());
                item.setJobName(jobDo.getName());
                return;
            }
        }

        if(StringUtils.isBlank(item.getJobName()) && StringUtils.isNotBlank(item.getJobCode())){
            Optional<JobDo> mbJobInfo = item.getJobDoList().stream().filter(i ->item.getJobCode().equalsIgnoreCase(i.getCode())).findFirst();
            if (!mbJobInfo.isPresent()) {
                JobDo bo = new JobDo();
                bo.setName(item.getJobName());
                bo.setCode(item.getJobCode());
                needInsertJobList.add((T) bo);
                return;
            }
        }

        // 填充 岗位id
        if(StringUtils.isNotBlank(item.getJobCode())){
            JobDo jobDo = jobMapper.getByCode(item.getJobCode());
            if(jobDo!=null){
                item.setJobId(jobDo.getId());
                item.setJobCode(jobDo.getCode());
                item.setJobName(jobDo.getName());
                return;
            }
        }

    }

    public <K> Map<K, JobBo> convertToJobBo(String tableName, String field, List<String> Fields,Boolean checkDelete,Function<JobDo, K> fieldMapper) {
        List<JobDo> jobDoList = excelImportUtil.selectByAllFieldInList(tableName, field, Fields, checkDelete);
        // 查询岗位组织关系
        List<JobOrgRelationDo> jobOrgRelationDoList = jobOrgRelationMapper.listAll();
        Map<Long, List<String>> jobOrgRelationMap = jobOrgRelationDoList
                .stream().collect(Collectors.groupingBy(JobOrgRelationDo::getJobId, Collectors.mapping(JobOrgRelationDo::getOrgId, Collectors.toList())));

        Map<K, JobBo> map = new HashMap<>();
        for (JobDo jobDo : jobDoList) {
            K key = fieldMapper.apply(jobDo);
            JobBo jobBo = new JobBo(jobDo.getId(), jobDo.getName(), jobDo.getCode(), jobOrgRelationMap.get(jobDo.getId()), jobDo.getJobTypeId());
            map.put(key, jobBo);
        }
        return map;
    }

    @Override
    public void preWriteDB(List<SyncEmployeeInfoBo> list,List<T> preInsertList) {
        // 先更具需要新增的数据类型分类
        List<JobDo> needJobInsertList = new ArrayList<>();
        List<MbPostInfo> needPostInsertList = new ArrayList<>();
        for (int i = 0; i < preInsertList.size(); i++) {
            T t = preInsertList.get(i);
            if(t instanceof JobDo){
                needJobInsertList.add((JobDo) t);
            }
            if(t instanceof MbPostInfo){
                needPostInsertList.add((MbPostInfo) t);
            }
        }

        List<JobDo> distinctJobList = needJobInsertList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() ->
                                new TreeSet<>(Comparator.comparing(JobDo::getCode, Comparator.nullsLast(String::compareTo))
                                        .thenComparing(JobDo::getName, Comparator.nullsLast(String::compareTo)))),
                        ArrayList::new
                ));
        List<MbPostInfo> distinctPostList = needPostInsertList.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() ->
                                new TreeSet<>(Comparator.comparing(MbPostInfo::getCode, Comparator.nullsLast(String::compareTo))
                                        .thenComparing(MbPostInfo::getName, Comparator.nullsLast(String::compareTo)))),
                        ArrayList::new
                ));
        // 写入岗位
        HashMap<String,Long> jobInfoMappingIdMap = new HashMap<>();
        preWriteJobDbAndBuildIds(list, distinctJobList, jobInfoMappingIdMap);


        // 写入职级
        HashMap<String,Long> postInfoMappingIdMap = new HashMap<>();
        preWritePostDbAndBuildIds(list, distinctPostList, postInfoMappingIdMap);

    }

    private void preWritePostDbAndBuildIds(List<SyncEmployeeInfoBo> list, List<MbPostInfo> distinctPostList, HashMap<String, Long> postInfoMappingIdMap) {
        for (int i = 0; i < distinctPostList.size(); i++) {
            MbPostInfo item = distinctPostList.get(i);
            postService.createPostAndReturn(item);

            String key = Optional.ofNullable(item.getCode())
                    .orElse("") // 如果jobDo.getCode()为null，则返回空字符串
                    .concat(Optional.ofNullable(item.getName())
                            .orElse("")); // 如果jobDo.getName()为null，则返回空字符串
            postInfoMappingIdMap.put(key, item.getId());
        }

        for (int i = 0; i < list.size(); i++) {
            SyncEmployeeInfoBo item = list.get(i);
            String key = Optional.ofNullable(item.getPostCode())
                    .orElse("") // 如果jobDo.getCode()为null，则返回空字符串
                    .concat(Optional.ofNullable(item.getPostName())
                            .orElse("")); // 如果jobDo.getName()为null，则返回空字符串

            if(postInfoMappingIdMap.containsKey(key)){
                item.setPostId(postInfoMappingIdMap.get(key));
            }
        }
    }

    private void preWriteJobDbAndBuildIds(List<SyncEmployeeInfoBo> list, List<JobDo> distinctJobList, HashMap<String, Long> jobInfoMappingIdMap) {
        for (int i = 0; i < distinctJobList.size(); i++) {
            JobDo item = distinctJobList.get(i);
            JobDo jobDo = jobMapper.getByName(item.getName());
            if(jobDo == null){
                jobMapper.create(item);
            }else {
                BeanUtils.copyProperties(jobDo,item);
            }

            String key = Optional.ofNullable(item.getCode())
                    .orElse("") // 如果jobDo.getCode()为null，则返回空字符串
                    .concat(Optional.ofNullable(item.getName())
                            .orElse("")); // 如果jobDo.getName()为null，则返回空字符串
            jobInfoMappingIdMap.put(key, item.getId());
        }

        for (int i = 0; i < list.size(); i++) {
            SyncEmployeeInfoBo item = list.get(i);
            String key = Optional.ofNullable(item.getJobCode())
                    .orElse("") // 如果jobDo.getCode()为null，则返回空字符串
                    .concat(Optional.ofNullable(item.getJobName())
                            .orElse("")); // 如果jobDo.getName()为null，则返回空字符串

            if(jobInfoMappingIdMap.containsKey(key)){
                item.setJobId(jobInfoMappingIdMap.get(key));
            }
        }
    }


    public ServiceErrorEnum checkSuperiorInfo(String superiorUid, Map<String, List<SyncEmployeeInfoBo>> uidInfoMap) {
        if (StringUtils.isNotBlank(superiorUid)) {
            MbOrgEmployeeInfo employeeInfo = organizationEmployeeService.findByUid(superiorUid);
            //数据库中和excel表中不存在时报错
            if (Objects.isNull(employeeInfo)) {
                List<SyncEmployeeInfoBo> superiorInfo = uidInfoMap.get(superiorUid);
                if (CollectionUtils.isEmpty(superiorInfo)) {
                    return ServiceErrorEnum.SYNCHUMANRESOURCES_SYNCEMPLOYEEINFO_SUPERIOR_FAILURE;
                }
            }
        }
        return ServiceErrorEnum.Success;
    }

    public ServiceErrorEnum checkEmployeeRoleName(SyncEmployeeInfoBo item) {
        List<MbRole> mbRoles =  item.getMbRoleList();
        if (CollectionUtils.isNotEmpty(mbRoles) && StringUtils.isNotBlank(item.getRoleName())) {
            long count = mbRoles.stream().filter(t -> t.getName().equalsIgnoreCase(item.getRoleName())).count();
            if (count < 1) {
                return ServiceErrorEnum.SyncHumanResources_SyncEmployeeInfo_RoleName_Failure;
            }
        }
        return ServiceErrorEnum.Success;
    }

    public void checkPostFromDb(List<SyncEmployeeCallBackRequestEntity.FailInfo> errorList, List<T> needInsertPostList,SyncEmployeeInfoBo item) {
        // 填写了职级编号和职级名称 根据职级编号判断该职级是否存在于所属公司职级中
        // 不存在创建一个职级；
        // 存在则校验职级编号和职级名称是否与所属公司职级中岗位名称一致，一致则校验通过，不一致则错误提示：职级编号和职级名称不存在，且不可导入
        if(StringUtils.isNotBlank(item.getPostCode()) && StringUtils.isNotBlank(item.getPostName())){
            Optional<MbPostInfo> mbPostInfo = item.getMbPostList().stream().filter(i -> item.getPostCode().equalsIgnoreCase(i.getCode())).findFirst();
            if (mbPostInfo.isPresent() && !mbPostInfo.get().getName().equals(item.getPostName())) {

                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(item.getLineNo());
                errorLog.setLineNo(item.getLineNo());
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.EMP.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.EMP.getIndex());
                errorLog.setFailReason("职级编号和职级名称不存在，且不可导入");
                errorList.add(errorLog);
                return;
            }
            if (!mbPostInfo.isPresent()) {
                MbPostInfo bo = new MbPostInfo();
                bo.setName(item.getPostName());
                bo.setCode(item.getPostCode());
                bo.setOrgId(item.getFirstCorgId());
                needInsertPostList.add((T) bo);
                return;
            }
        }

        //若没有填写职级编号，填写了职级名称，则根据职级名称判断该职级是否存在于所属公司职级中，
        //不存在创建一个职级；
        //存在则校验通过；
        if(StringUtils.isBlank(item.getPostCode()) && StringUtils.isNotBlank(item.getPostName())){
            Optional<MbPostInfo> mbPostInfo = item.getMbPostList().stream().filter(i ->item.getPostName().equalsIgnoreCase(i.getName())).findFirst();
            if (!mbPostInfo.isPresent()) {
                MbPostInfo bo = new MbPostInfo();
                bo.setName(item.getPostName());
                bo.setCode(item.getPostCode());
                bo.setOrgId(item.getFirstCorgId());
                needInsertPostList.add((T) bo);
                return;
            }
        }
        // 填充 职级id
        if(StringUtils.isNotBlank(item.getPostName()) && StringUtils.isNotBlank(item.getFirstCorgId())){
            MbPostInfo postInfo = postService.findByNameAndOrgId(item.getPostName(), item.getFirstCorgId());
            if(postInfo!=null){
                item.setPostId(postInfo.getId());
                return;
            }
        }

        //若没有填写职级名称，填写了职级编号，则根据职级编号判断该职级是否存在于所属公司职级中，
        //不存在创建一个职级；
        //存在则校验通过；
        if(StringUtils.isBlank(item.getPostName()) && StringUtils.isNotBlank(item.getPostCode())){
            Optional<MbPostInfo> mbPostInfo = item.getMbPostList().stream().filter(i ->item.getPostCode().equalsIgnoreCase(i.getCode())).findFirst();
            if (!mbPostInfo.isPresent()) {
                MbPostInfo bo = new MbPostInfo();
                bo.setName(item.getPostName());
                bo.setCode(item.getPostCode());
                bo.setOrgId(item.getFirstCorgId());
                needInsertPostList.add((T) bo);
                return;
            }
        }
        // 填充 职级id
        if(StringUtils.isNotBlank(item.getPostCode()) && StringUtils.isNotBlank(item.getFirstCorgId())){
            MbPostInfo postInfo = postService.findByCodeAndOrgId(item.getPostCode(), item.getFirstCorgId());
            if(postInfo!=null){
                item.setPostId(postInfo.getId());
                return;
            }
        }

    }


    @Override
    public void writeErrorLog(List<SyncEmployeeCallBackRequestEntity.FailInfo> failInfoList, MbImportExcelRecord mbImportExcelRecord) {

    }




    @Override
    public String getTag() {
        return "employ_add_v1";
    }

    @Override
    public ExcelImportConfig getConfig() {
        ExcelImportConfig config = new ExcelImportConfig();
        config.setIsSharding(true);
        config.setIgnoreHeader(true);
        config.setRollBackType(1);
        return config;
    }


    private void confirmGenderAndBirthDay(Map<String, List<EmployeeCardTypeInfoColumnVO>> empCardMap, List<EmployeeInfoExcelColumnVO> employeeInfo) {
        employeeInfo.forEach(e ->{
            if (empCardMap.containsKey(e.getUid()) && CollectionUtils.isNotEmpty(empCardMap.get(e.getUid()))) {
                // 特定类型的证件号码转大写
                empCardMap.get(e.getUid()).forEach(k ->{
                    if (CardEnum.needUpperCaseCard(k.getCardType())){
                        k.setCardNo(k.getCardNo().toUpperCase());
                    }
                });
                //根据身份证号码确定性别生日信息
                List<EmployeeCardTypeInfoColumnVO> idCards = empCardMap.get(e.getUid()).stream().filter(k -> CardEnum.ID_CARD.getName().equals(k.getCardType())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(idCards)) {
                    try {
                        String cardNo = idCards.get(0).getCardNo();
                        e.setBirthday(IdCardUtil.getBirth(cardNo));
                        e.setGender(IdCardUtil.getGender(cardNo));
                    }catch (Exception ex){
                        log.error("身份证转换身份性别异常",ex);
                    }

                }
            }
        });
    }


    private  SyncEmployeeInfoBo buildEmployeeInfoBo(Map<String, List<EmployeeCardTypeInfoColumnVO>> empCardMap, EmployeeInfoExcelColumnVO item) {
        SyncEmployeeInfoBo employeeInfoBo = new SyncEmployeeInfoBo();

        employeeInfoBo.setLineNo(item.getLineNo());
        employeeInfoBo.setIsDelete(false);
        employeeInfoBo.setUid(item.getUid());
        employeeInfoBo.setName(item.getName());
        employeeInfoBo.setLastName(item.getLastName());
        employeeInfoBo.setFirstName(item.getFirstName());
        if (StringUtils.isEmpty(item.getCountryCode())) {
            employeeInfoBo.setCountryCode(PhoneCountryCodeEnum.CN.getCountryCode());
        } else {
            int contryCode = item.getCountryCode().indexOf("+");
            employeeInfoBo.setCountryCode(contryCode>-1? item.getCountryCode().substring(contryCode):"+86");
        }
        employeeInfoBo.setMobilePhone(item.getMobilePhone());
        // employeeInfoBo.setPassword(item.getPassword());
        employeeInfoBo.setBirthday(item.getBirthday());
        employeeInfoBo.setGender(F.getDesc().equals(item.getGender()) ? F.getCode() : M.getCode());
        employeeInfoBo.setEmail(item.getEmail());
        NationalityEnum nationalityEnum = Optional.ofNullable(NationalityEnum.getByCode(item.getNationality())).orElse(NationalityEnum.CN);
        employeeInfoBo.setNationality(nationalityEnum.getCode());
        employeeInfoBo.setCreditCardNumbers(null);
        employeeInfoBo.setBusinessCode(item.getBusinessCode());
        employeeInfoBo.setPostName(item.getPostName());
        employeeInfoBo.setPostCode(item.getPostCode());

        List<SyncEmployeeInfoBo.SyncEmployeeCardInfoBo> idCardInfoBoList = new ArrayList<>();
        List<EmployeeCardTypeInfoColumnVO> idCardInfoList = empCardMap.get(item.getUid());
        if (CollectionUtils.isNotEmpty(idCardInfoList)) {
            for (EmployeeCardTypeInfoColumnVO carInfo : idCardInfoList) {
                SyncEmployeeInfoBo.SyncEmployeeCardInfoBo cardInfoBo = new SyncEmployeeInfoBo.SyncEmployeeCardInfoBo();
                cardInfoBo.setLineNo(carInfo.getLineNo());
                cardInfoBo.setCardType(carInfo.getCardType());
                cardInfoBo.setCardNo(carInfo.getCardNo());
                cardInfoBo.setTimeLimit(carInfo.getTimeLimit());
                cardInfoBo.setUid(carInfo.getUid());
                cardInfoBo.setPlaceOfIssue(carInfo.getPlaceOfIssue());
                idCardInfoBoList.add(cardInfoBo);
            }
        }
        employeeInfoBo.setCardInfoList(idCardInfoBoList);
        employeeInfoBo.setRoleName(item.getRoleName());
        employeeInfoBo.setEmployeeType(ApplyTripEmployeeEnum.getCodeByName(item.getEmployeeType()));
        employeeInfoBo.setManageUid(item.getManageUid());
        employeeInfoBo.setJobCode(item.getJobCode());
        employeeInfoBo.setJobName(item.getJobName());
        employeeInfoBo.setGender(Optional.ofNullable(employeeInfoBo.getGender()).orElse(GenderEnum.M.getCode()));
        //手机区号
        PhoneCountryCodeEnum phoneCountryCodeEnum = StringUtils.isEmpty(employeeInfoBo.getCountryCode()) ? null : PhoneCountryCodeEnum.getByCountryCode(employeeInfoBo.getCountryCode());
        if (phoneCountryCodeEnum == null) {
            employeeInfoBo.setCountryCode(PhoneCountryCodeEnum.CN.getCountryCode());
        }
        return employeeInfoBo;
    }

    public void checkEmployeeCardInfo(SyncEmployeeInfoBo employee, List<SyncEmployeeCallBackRequestEntity.FailInfo> errorList) {
        for (SyncEmployeeInfoBo.SyncEmployeeCardInfoBo cardType : employee.getCardInfoList()) {
            // 卡片基本信息不能为空
            if (StringUtils.isEmpty(cardType.getCardNo()) || cardType == null || cardType.getCardType() == null) {
                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(employee.getLineNo());
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.CARD.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.CARD.getIndex());
                errorLog.setLineNo(cardType.getLineNo());
                errorLog.setFailReason(ServiceErrorEnum.SyncHumanResources_SyncEmployeeInfo_EmptyCardType_Failure.getErrorMessage());
                errorList.add(errorLog);
            }

            // 证件类型超出赋值范围
            if (Objects.isNull(CardEnum.getByName(cardType.getCardType()))) {
                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(employee.getLineNo());
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.CARD.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.CARD.getIndex());
                errorLog.setLineNo(cardType.getLineNo());
                errorLog.setFailReason(ServiceErrorEnum.SyncHumanResources_SyncEmployeeInfo_OutOfCardType_Failure.getErrorMessage());
                errorList.add(errorLog);
            }else {
                cardType.setCardType(CardEnum.getByName(cardType.getCardType()).getType());
            }


            // 证件类型为护照或国际海员证时，证件签发国是否为空，为空则不可上传，失败原因：证件签发国不可为空；
            boolean passportOrInternalSeafarer = CardEnum.PASSPROT.getType().equals(cardType.getCardType()) ||
                    CardEnum.INTERNAL_SEAFARER_CARD.getType().equals(cardType.getCardType());
            if (passportOrInternalSeafarer && StringUtils.isBlank(cardType.getPlaceOfIssue())) {
                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(employee.getLineNo());
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.CARD.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.CARD.getIndex());
                errorLog.setLineNo(cardType.getLineNo());
                errorLog.setFailReason(ServiceErrorEnum.SyncHumanResources_SyncEmployeeInfo_EmptyCardTypePlaceOfIssue_Failure.getErrorMessage());
                errorList.add(errorLog);
            }

            //护照、军人证、回乡证、台胞证、港澳通行证、旅行证、外国人永久居留身份证、其他时证件到期日期不可为空，为空则不可上传
            // 失败原因：证件到期日期不可为空；
            boolean needTimeLimitVerify = CardEnum.PASSPROT.getType().equals(cardType.getCardType()) ||
                    CardEnum.SOLDIER_CARD.getType().equals(cardType.getCardType()) ||
                    CardEnum.RETURN_HOME_CARD.getType().equals(cardType.getCardType()) ||
                    CardEnum.TAIWAN_CARD.getType().equals(cardType.getCardType()) ||
                    CardEnum.GANGAO_CARD.getType().equals(cardType.getCardType()) ||
                    CardEnum.TRAVEL_CARD.getType().equals(cardType.getCardType()) ||
                    CardEnum.FOREIGNER_LIVE_CARD.getType().equals(cardType.getCardType()) ||
                    CardEnum.ELSE.getType().equals(cardType.getCardType());
            if (needTimeLimitVerify && StringUtils.isBlank(cardType.getTimeLimit())) {

                SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                errorLog.setMainLineNo(employee.getLineNo());
                errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.CARD.getName());
                errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.CARD.getIndex());
                errorLog.setLineNo(cardType.getLineNo());
                errorLog.setFailReason(ServiceErrorEnum.SyncHumanResources_SyncEmployeeInfo_EmptyCardTypeTimeLimit_Failure.getErrorMessage());
                errorList.add(errorLog);
            }

            // 证件有效期超出日期范围
            if (StringUtils.isNotBlank(cardType.getTimeLimit())) {
                if(!CommonQlFunction.isValidDate(cardType.getTimeLimit(),  DateUtil.DF_YMD)) {
                    SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                    errorLog.setMainLineNo(employee.getLineNo());
                    errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.CARD.getName());
                    errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.CARD.getIndex());
                    errorLog.setLineNo(cardType.getLineNo());
                    errorLog.setFailReason(ServiceErrorEnum.SyncHumanResources_SyncEmployeeInfo_EmptyCardTypeTimeFormat_Failure.getErrorMessage());
                    errorList.add(errorLog);
                }
            }

            //增加身份证校验
            if (Objects.equals(CardEnum.ID_CARD.getType(), cardType.getCardType())) {
                //身份证正则
                if (!cardType.getCardNo().matches(RegularExpressionConst.CARD)) {
                    SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                    errorLog.setMainLineNo(employee.getLineNo());
                    errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.CARD.getName());
                    errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.CARD.getIndex());
                    errorLog.setLineNo(cardType.getLineNo());
                    errorLog.setFailReason(ServiceErrorEnum.SyncHumanResources_SyncEmployeeInfo_ContactInfo_IdCard_Failure.getErrorMessage());
                    errorList.add(errorLog);
                }
                //身份证和生日
                if (!IdCardUtil.validDate(cardType.getCardNo(), employee.getBirthday())) {
                    SyncEmployeeCallBackRequestEntity.FailInfo errorLog = new SyncEmployeeCallBackRequestEntity.FailInfo();
                    errorLog.setMainLineNo(employee.getLineNo());
                    errorLog.setSheetName(SyncEmployeeInfoBo.SheetEnum.CARD.getName());
                    errorLog.setSheetIndex(SyncEmployeeInfoBo.SheetEnum.CARD.getIndex());
                    errorLog.setLineNo(cardType.getLineNo());
                    errorLog.setFailReason(ServiceErrorEnum.SyncHumanResources_SyncEmployeeInfo_ContactInfo_IdCard_Birthday_Failure.getErrorMessage());
                    errorList.add(errorLog);
                }

                //以身份证性别为准 覆盖处理
                String sex = IdCardUtil.getSex(cardType.getCardNo());
                employee.setGender("男".equals(sex) ? GenderEnum.M.getCode() : GenderEnum.F.getCode());

            }
        }
    }

}
